<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1>原生JS的Redux核心示例</h1>

    <div id="app">
      <p>点击了 <span id="span">0</span> 次</p>

      <button id="btn1">+</button>
      <button id="btn2">-</button>
      <button id="btn3">自增 of 奇数</button>
      <button id="btn4">自增 async</button>
    </div>

    <!-- 引入 Redux 的核心类库 -->
    <script src="https://unpkg.com/redux@4.0.1/dist/redux.min.js"></script>

    <script type="module">
      // console.log("redux", Redux);

      const defaultState = {
        msg: "~",
        count: 100,
      };

      /**
       * 1. 定义一个 reducer 纯函数，它是用于管理 store 的 state 数据
       *
       * 参数：
       *   1. state   - 上一次仓库中的 state 数据
       *   2. action  - 当派发一个动作时，会触发该 reducer ,那么动作就是第二个参数
       *
       * 返回值：
       *   可以根据当前 action 的类型不同，来返回一份全新的 state 数据
       *
       * 触发时机：
       *    1. 不同于 React 中的 useReducer hook 的 reducer 必须是派发动作后再触发
       *      这里 redux 中的 reducer 默认在仓库 store 时就会触发一次
       *      state 为 undefined
       *      action 中的 type 是一个 redux 生成的随机字符串
       *    2. 当 store.dispatch(action) 被调用时，触发
       */
      function reducer(state = defaultState, action) {
        console.group("reducer");
        console.log("state", state);
        console.log("action", action);
        console.groupEnd("reducer");

        switch (action.type) {
          case "INCREMENT":
            return {
              ...state,
              count: state.count + 1,
            };

          case "DECREMENT":
            return {
              ...state,
              count: state.count - 1,
            };

          default:
            return state;
        }
      }

      /**
       * 2. Redux.createStore() 创建 store
       *
       * store: {
       *    dispatch: 一个函数，用于派发动作
       *    getState: 一个函数，用于获取当前 store 中的 state 数据
       *    subscribe: 一个函数，用于订阅仓库数据的更新
       *    replaceReducer: 一个函数，用于替换当前仓库的 reducer 函数
       * }
       */
      const store = Redux.createStore(reducer);

      // console.log("store中state", store.getState());

      /**
       * 3. 使用 store 中数据去渲染页面
       *
       * 同时对 store 做订阅
       *
       * store.subscribe(listener)
       */
      function render() {
        // 1. 获取 store 的 state
        const { msg, count } = store.getState();

        // 2. 获取 span 的 dom 元素
        const spanEl = document.querySelector("#span");

        // 3. 设置它的 innerHTML
        spanEl.innerHTML = count;
      }
      render();

      store.subscribe(() => {
        // console.log("仓库数据更新了");
        render();
      });

      /**
       * 4. 给页面中的 btn 处理点击事件，修改 store 的 state 数据
       *
       * PS: store 的 state 只能通过 reducer 函数来更新，而 reducer 函数的触发是由 store.dispatch 去派发的
       *
       */
      btn1.onclick = function () {
        store.dispatch({
          // 动作对象
          type: "INCREMENT",
        });

        // 查看最新仓库数据
        // console.log("state", store.getState());
      };

      btn2.onclick = function () {
        store.dispatch({
          // 动作对象
          type: "DECREMENT",
        });
      };

      btn3.onclick = function () {
        if (store.getState().count % 2 !== 0) {
          store.dispatch({
            // 动作对象
            type: "INCREMENT",
          });
        }
      };

      btn4.onclick = function () {
        setTimeout(() => {
          store.dispatch({
            // 动作对象
            type: "INCREMENT",
          });
        }, 500);
      };
    </script>
  </body>
</html>
